#! /usr/bin/python
# -*- coding:utf-8 -*-

import requests
from bs4 import BeautifulSoup
import re


class Baidubaoche(object):
    def __init__(self):
        self._sess = requests.session()
        self._init_default_headers()

    def login(self, user, pwd):
        url = 'http://www.baidubaoche.com/webapp/account'
        self.update_headers({'Referer': 'http://www.baidubaoche.com/webapp/account',
                             'Host': 'www.baidubaoche.com',
                             'Origin': 'http://www.baidubaoche.com'})
        data = {'telephone': user, 'password': pwd, 'redirect': ''}
        resp = self._sess.post(url, data=data)
        resp.encoding = 'utf-8'
        soup = BeautifulSoup(resp.text, 'lxml')

        title = soup.title
        if not title or title.string != 'AA巴士':
            return False

        header_title = soup.select_one('div.header')
        if header_title and header_title.string == '用户登录':
            return False

        nick = soup.select_one('div.user-info > a > p').string
        span = soup.select_one('div.user-info > a > span').string
        print(nick, '登录成功！')
        print('当前积分:', span)

        return True

    def _get_cities(self, html):
        soup = BeautifulSoup(html, 'lxml')
        cities = []
        for li in soup.select('body > ul.cities > li'):
            href = li.a['href']
            name = li.a.string
            cities.append((href, name))
        return cities

    def get_to_cities(self, refer_url):
        """

        :return: 到达城市列表
        """
        city_url = 'http://www.baidubaoche.com/webapp/index/cities/to/1'
        self.update_headers({'Referer': refer_url})
        resp = self._sess.get(city_url)
        resp.encoding = 'utf-8'
        return self._get_cities(resp.text)

    def confirm_to_city(self, city_url):
        refer_url = 'http://www.baidubaoche.com/webapp/index/cities/to/1'
        self.update_headers({'Referer': refer_url})
        return self._sess.get(city_url)

    def get_from_cities(self):
        pre_url = 'http://www.baidubaoche.com/webapp/index/city'
        self.update_headers({'Referer': 'http://www.baidubaoche.com/webapp'})
        self._sess.post(pre_url, data={'longitude': '', 'latitude': ''})

        city_url = 'http://www.baidubaoche.com/webapp/index/cities'
        resp = self._sess.get(city_url)
        resp.encoding = 'utf-8'
        return self._get_cities(resp.text)

    def confirm_from_city(self, city_url):
        refer_url = 'http://www.baidubaoche.com/webapp/index/cities'
        self.update_headers({'Referer': refer_url})
        self._sess.get(city_url)

    def get_pickup_point(self, line_date, refer_url):
        line_url = 'http://www.baidubaoche.com/webapp/line/search/date/' + line_date
        self.update_headers({'Referer': refer_url})
        resp = self._sess.get(line_url)
        resp.encoding = 'utf-8'
        soup = BeautifulSoup(resp.text, 'lxml')
        trs = soup.select('div.station-select > table.stations > tr[onclick]')
        stations = []
        for tr in trs:
            line_id = re.search('\d+', tr['onclick']).group(0)
            name = tr.select_one('td + td + td').string
            stations.append((line_id, name))
        return stations

    def correct_schedule(self, html):
        pass

    def prepare_order(self, from_station=None,
                      to_station=None, line_id=None, line_date=None):
        """
        广州: 4
        珠海: 5
        """
        line_url = 'http://www.baidubaoche.com/webapp/line/schedule/from_station/{0}/to_station/{1}/line_id/{2}/date/{3}'.format(
            from_station, to_station, line_id, line_date)

        self.update_headers({'Referer': 'http://www.baidubaoche.com/webapp/line/search/date/' + line_date})

        resp = self._sess.get(line_url)
        if resp.status_code != 200:
            return False
        resp.encoding = 'utf-8'
        soup = BeautifulSoup(resp.text, 'lxml')

        ticket_list = list()
        schedule_list = soup.select('ul.schedule-list > li')
        for li in schedule_list:
            ticket = list()
            tr1 = li.select_one('table > tr')
            tr1_tds = tr1.select('td')
            ticket.append(tr1_tds[2].string)  # 时间

            status = list()
            for p in tr1_tds[3].select('p'):

                p_child = p.select_one('> *')

                if p_child.has_attr('href'):
                    status.append((p_child.string, p_child['href']))  # 状态
                else:
                    status.append((p_child.string, None))
            ticket.append(status)

            tr2 = li.select_one('table > tr + tr')
            ticket.append(tr2.select_one('td + td + td').string)  # 出发

            tr3 = li.select_one('table > tr + tr + tr')
            ticket.append(tr3.select_one('td + td + td').string)  # 到达

            ticket_list.append(ticket)

        return ticket_list

    def order_ticket(self, quantity, customer_coupon_id, payment, schedule_id, refer_url):
        """

        :param quantity: 票数
        :param customer_coupon_id: 优惠券
        :param payment: 2 上车支付; 3 微信支付
        :param schedule_id: 线路id
        :param refer_url: 引用链接
        :return: bool True订票成功 False订票失败
        """
        order_url = 'http://www.baidubaoche.com/webapp/line/preview'
        self.update_headers({'Referer': refer_url})
        data = {'quantity': quantity, 'customer_coupon_id': customer_coupon_id,
                'payment': payment, 'schedule_id': schedule_id}
        resp_pay = self._sess.post(order_url, data)
        if resp_pay.status_code == 200:
            print('订票成功，请立即支付订单')
            return True
        else:
            return False

    def get_line_date(self, html):
        soup = BeautifulSoup(html, 'lxml')
        line_dates = soup.select_one('select[name="date"]')
        dates = list()
        for option in line_dates.select('> *'):
            dates.append((option['value'], option.text))
        return dates

    def prompt_order(self):
        import getpass

        user = input('请输入用户名:')
        pwd = getpass.getpass('请输入密码:')
        if not self.login(user, pwd):
            print('登录失败')
            return False
        del user
        del pwd

        from_stations = self.get_from_cities()
        for index in range(len(from_stations)):
            print(index, from_stations[index])
        from_station = from_stations[int(input('请选择出发城市:'))]
        self.confirm_from_city(from_station[0])

        to_stations = self.get_to_cities(from_station[0])
        for index in range(len(to_stations)):
            print(index, to_stations[index])
        to_station = to_stations[int(input('请选择到达城市:'))]
        resp = self.confirm_to_city(to_station[0])

        resp.encoding = 'utf-8'
        line_dates = self.get_line_date(resp.text)
        for index in range(len(line_dates)):
            print(index, line_dates[index])
        line_date = line_dates[int(input('请输入乘车日期:'))]

        pickup_points = self.get_pickup_point(line_date[0], to_station[0])
        for index in range(len(pickup_points)):
            print(index, pickup_points[index])
        geton_point = pickup_points[int(input('请选择上车点:'))]
        getoff_point = pickup_points[int(input('请选择下车点:'))]

        line_id = '10'

        orders = self.prepare_order(geton_point[0], getoff_point[0], line_id, line_date[0])
        for index in range(len(orders)):
            print(index, orders[index])
        order = orders[int(input('请选择发车时间:'))]

        for index in range(len(order[1])):
            print(index, order[1][index])
        order_price = order[1][int(input('请选择票价:'))]

        if order_price[1] is None:
            print('当前车次不可预定')
            return False
        schedule_id = re.search('\d+', order_price[1]).group(0)

        quantity = 1
        customer_coupon_id = 0
        payment = 3
        return self.order_ticket(quantity, customer_coupon_id, payment, schedule_id, order_price[1])

    def _init_default_headers(self):
        self._sess.headers = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Accept-Encoding': 'gzip, deflate',
            'Connection': 'keep-alive',
            'Content-Type': 'application/x-www-form-urlencoded',
            'Origin': 'http://www.baidubaoche.com',
            'User-Agent': 'Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19'
        }

    def update_headers(self, new_header):
        assert type(new_header) is dict
        self._sess.headers.update(new_header)


def main():
    baidu = Baidubaoche()
    baidu.prompt_order()

if __name__ == '__main__':
    main()
